package vip.liux.contracts.security.core;

import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import vip.liux.contracts.models.identity.IdentityRole;
import vip.liux.contracts.models.identity.RoleDomainManager;
import vip.liux.contracts.security.core.extensions.IdentityError;
import vip.liux.contracts.security.core.extensions.IdentityErrorDescriber;
import vip.liux.contracts.security.core.extensions.IdentityResult;

import java.util.ArrayList;
import java.util.List;

/**
 * 角色验证器接口
 * <p>定义了验证角色的操作。</p>
 */
public interface IRoleValidator {

    /**
     * 验证角色
     *
     * @param manager 角色领域管理器
     * @param role    角色对象
     * @return 验证结果
     */
    IdentityResult validate(RoleDomainManager manager, IdentityRole role);

    /**
     * 角色验证器实现类
     * <p>提供了默认的角色验证逻辑。</p>
     */
    class RoleValidator {

        /**
         * 错误描述器
         */
        private final IdentityErrorDescriber describer;

        /**
         * 使用指定的错误描述器构造角色验证器
         *
         * @param describer 错误描述器
         */
        public RoleValidator(IdentityErrorDescriber describer) {
            this.describer = describer;
        }

        /**
         * 使用默认的错误描述器构造角色验证器
         */
        public RoleValidator() {
            this.describer = new IdentityErrorDescriber();
        }

        /**
         * 验证角色
         *
         * @param manager 角色领域管理器
         * @param role    角色对象
         * @return 验证结果
         */
        public IdentityResult validate(RoleDomainManager manager, IdentityRole role) {
            Assert.notNull(manager, "manager must not be null");
            Assert.notNull(role, "role must not be null");

            List<IdentityError> errors = new ArrayList<>();

            validateRoleName(manager, role, errors);

            if (!errors.isEmpty()) {
                return IdentityResult.failed(errors);
            }
            return IdentityResult.success();
        }

        /**
         * 验证角色名称
         *
         * @param manager 角色领域管理器
         * @param role    角色对象
         * @param errors  错误列表
         */
        private void validateRoleName(RoleDomainManager manager, IdentityRole role,
                                      List<IdentityError> errors) {
            var roleName = manager.getRoleName(role);
            if (StringUtils.isBlank(roleName)) {
                errors.add(describer.invalidRoleName(roleName));
            } else {
                var owner = manager.findByRoleName(roleName);
                if (owner != null &&
                        !StringUtils.equals(manager.getRoleId(owner), manager.getRoleId(role))) {
                    errors.add(describer.duplicateRoleName(roleName));
                }
            }
        }
    }
}